#ifndef GPS_H_
#define GPS_H_

#include <vector>
#include <string>
#include <stdexcept>
#include "../Communication/DataStream.h"
#include "../Math/Math.h"
#include "GeoCoord.h"

namespace uav
{
namespace nav
{

using namespace comm;
using namespace math;

/**
 * @class Gps
 *
 * @brief GPS device driver class.
 *
 * This class is intended for use with the Garmin GPS 18 and GPS 18x devices
 * connected to a serial port. It currently supports the GPGGA (position fix
 * data) and PGRMV (3d velocity) sentences.
 *
 * @author Travis Portz
 */
class Gps
{
public:

	enum FixQuality
	{
		FIX_QUALITY_NONE = 0, ///< Fix not available.
		FIX_QUALITY_BASIC = 1, ///< Non-differential fix.
		FIX_QUALITY_DIFFERENTIAL = 2, ///< Differential (WAAS) fix.
		FIX_QUALITY_ESTIMATED = 6 ///< Estimated (dead reckoning).
	};

	enum SentenceType
	{
		SENTENCE_GPGGA, ///< Position fix sentence (GPGGA).
		SENTENCE_PGRMV, ///< 3d velocity sentence (PGRMV).
		SENTENCE_UNKNOWN ///< Unknown/unsupported sentence.
	};

	/**
	 * Constructs a GPS object using the specified data stream as a source of NMEA sentences.
	 *
	 * The data stream will typically be a SerialPort instance. However, any
	 * type of data stream is allowed for testing purposes.
	 *
	 * If the data stream is a SerialPort instance, the serial port must be
	 * opened before any of the GPS functions are used.
	 *
	 */
	explicit Gps(DataStream &stream);

	/**
	 * Reads the next sentence from the GPS device and stores it internally.
	 */
	void nextSentence();

	/**
	 * Gets sentence type (first field) of the current NMEA sentence.
	 */
	SentenceType getSentenceType() const;

	/**
	 * Gets the fix quality of the current sentence.
	 *
	 * If the current sentence is not a GPGGA sentence, this function will
	 * return the fix quality obtained from the last GPGGA sentence or
	 * FIX_QUALITY_NONE if no GPGGA sentences have been read.
	 */
	FixQuality getFixQuality() const;

	/**
	 * Gets the position fix from a GPGGA sentence.
	 *
	 * This function should only be called if the current sentence is
	 * a GPGGA sentence and a fix is available.
	 */
	GeoCoord getPosition() const;

	/**
	 * Gets the 3d velocity from a PGRMV sentence.
	 *
	 * This function should only be called if the current sentence is
	 * a PGRMV sentence and the last GPGGA sentence had a valid fix.
	 */
	Vector3 getVelocity() const;

private:
	DataStream &stream; ///< The data stream providing the GPS data (typically a SerialPort instance).
	std::vector<std::string> fields; ///< The fields of the current NMEA sentence.
	SentenceType type;
	FixQuality quality;
};

inline Gps::Gps(DataStream &stream) : stream(stream), type(SENTENCE_UNKNOWN), quality(FIX_QUALITY_NONE) {}

inline Gps::SentenceType Gps::getSentenceType() const
{
	return type;
}

inline Gps::FixQuality Gps::getFixQuality() const
{
	return quality;
}

}}

#endif
